/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.entitydataconvertor.method;


import com.inspur.edp.bff.designtime.generator.entitydataconvertor.VMObjectDataConvertorGenContext;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.generator.RefObject;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import lombok.var;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.Arrays;

public class GetChildDataConvertorMethodGenerator extends ClassMethodGenerator {

    private static final String param_ChildCode = "childCode";
    private VMObjectDataConvertorGenContext voDataConvertorGenContext;

    private boolean hasChild = false;

    public GetChildDataConvertorMethodGenerator(
            VMObjectDataConvertorGenContext voDataConvertorGenContext) {
        super();
        this.voDataConvertorGenContext = voDataConvertorGenContext;
    }

    @Override
    protected Block buildMethodBody() {

        Block block = ast.newBlock();
        SwitchStatement result = getSwitchBlock();
        ArrayList<Statement> statements = getChildCases();

        statements.addAll(getDefaultCase());
        result.statements().addAll(statements);
        return buildReturnBlock(hasChild, result);
    }

    private SwitchStatement getSwitchBlock() {
        SwitchStatement statement = ast.newSwitchStatement();
        statement.setExpression(ast.newSimpleName(param_ChildCode));
        return statement;
    }

    private ArrayList<Statement> getChildCases() {
        ArrayList<IGspCommonObject> childObjs = getAllChildObject(
                voDataConvertorGenContext.getTargetObject());
        ArrayList<Statement> statements = new ArrayList<>();
        for (IGspCommonObject item : childObjs) {
            hasChild = true;
            RefObject<GspViewObject> voObj = new RefObject<GspViewObject>(null);
            if (containBeObject(item.getID(), voObj)) {
                statements.addAll(getChildCase(item, voObj.argvalue));
            } else {
                statements.addAll(getBeChildCase(item));
            }
        }
        return statements;
    }

    private ArrayList<IGspCommonObject> getAllChildObject(IGspCommonObject targetObject) {
        ArrayList<IGspCommonObject> objects = new ArrayList<IGspCommonObject>();
        for (IGspCommonObject childObj : targetObject.getContainChildObjects()) {
            objects.add(childObj);
            ArrayList<IGspCommonObject> children = getAllChildObject(childObj);
            if (children != null && children.size() > 0) {
                objects.addAll(children);
            }
        }

        return objects;
    }

    private boolean containBeObject(String beObjId, RefObject<GspViewObject> voObj) {
        voObj.argvalue = null;
        for (IGspCommonObject childObj : voDataConvertorGenContext.getVmObject().getContainChildObjects()) {
            GspViewObject item = (GspViewObject) childObj;
            if (item == null)
                continue;
            if (!item.getIsVirtual() && beObjId.equals(item.getMapping().getTargetObjId())) {
                voObj.argvalue = item;
                return true;
            }
        }

        return false;
    }

    //        case object.Code:
//        * return new objectConvertor();
//        
    private ArrayList<Statement> getChildCase(IGspCommonObject beObj, GspViewObject vmObject) {

        ArrayList<Statement> statements = new ArrayList<>();

        statements.add(getSwitchCase(beObj.getCode()));

        String className = voDataConvertorGenContext.getChildGenerators().get(vmObject.getID()).getClassName();
        ReturnStatement returnStatement = ast.newReturnStatement();
        ClassInstanceCreation creation = ast.newClassInstanceCreation();
        creation.setType(ast.newSimpleType(ast.newSimpleName(className)));
        returnStatement.setExpression(creation);
        statements.add(returnStatement);

        return statements;
    }

    private SwitchCase getSwitchCase(String value) {
        StringLiteral caseValue = ast.newStringLiteral();
        caseValue.setLiteralValue(value);
        SwitchCase caseStatement = ast.newSwitchCase();
        caseStatement.setExpression(caseValue);

        return caseStatement;
    }

    private ArrayList<Statement> getBeChildCase(IGspCommonObject beObj) {

        ArrayList<Statement> statements = new ArrayList<>();

        statements.add(getSwitchCase(beObj.getCode()));

        statements.add(ExpressionUtils.getReturnNullStatement(ast));
        return statements;
    }

    private ArrayList<Statement> getDefaultCase() {

        ArrayList<Statement> statements = new ArrayList<>();
        var defaultCast = ast.newSwitchCase();
        defaultCast.setExpression(null);
        statements.add(defaultCast);
        statements.add(ExpressionUtils.getReturnNullStatement(ast));
//        statements.add(getExceptionStatement());
        return statements;
    }

    private Block buildReturnBlock(boolean hasChild, SwitchStatement result) {

        Block block = ast.newBlock();
        if (hasChild) {
            block.statements().add(result);
        } else {
            block.statements().add(ExpressionUtils.getReturnNullStatement(ast));
//            block.statements().add(getExceptionStatement());
        }
        return block;
    }

    private ThrowStatement getExceptionStatement() {
        addImport(CefException.class.getTypeName());
        ThrowStatement statement = GeneratorUtil.getThrowStatement(ast,"不存在子表",param_ChildCode,true);

//        ClassInstanceCreation invocation = ast.newClassInstanceCreation();
//        //invocation.setType(ast.newSimpleType(ast.newSimpleName("RuntimeException")));
//        invocation.setType(new TypeInfo(RuntimeException.class).getType(ast, voDataConvertorGenContext.getEntityGenContext()));
//
//        InfixExpression message = ast.newInfixExpression();
//        StringLiteral format = ast.newStringLiteral();
//        format.setLiteralValue("不存在子表");
//        message.setLeftOperand(format);
//        message.setOperator(InfixExpression.Operator.PLUS);
//        message.setRightOperand(ast.newSimpleName(param_ChildCode));
//
//        invocation.arguments().add(message);
//        statement.setExpression(invocation);

        return statement;
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        return new ArrayList<Modifier.ModifierKeyword>(Arrays.asList(
                new Modifier.ModifierKeyword[]{Modifier.ModifierKeyword.PUBLIC_KEYWORD}));
    }

    @Override
    protected boolean getIsOverride() {
        return true;
    }

    @Override
    protected String getMethodName() {
        return "getChildDataConvertor";
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        ParameterInfo param = new ParameterInfo();
        param.setParamType(new TypeInfo("String"));
        param.setParamName(param_ChildCode);
        return new ArrayList<ParameterInfo>(
                Arrays.asList(new ParameterInfo[]{param}));
    }

    @Override
    protected TypeInfo getReturnType() {

        TypeInfo typeInfo = new TypeInfo("AbstractDataConvertor");
        typeInfo.setTypePackageName("com.inspur.edp.bff.spi");
        return typeInfo;
    }
}
